﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Modeling;

namespace UofCASE.AgileProductLinerDSL {
    
    //TODO: validate unique names cross-feature models
    //TODO: in HTML report generation, print report for embedded features that contrain others
    //TODO: after connecting an alternative to a node, set the node occurence automatically to not apply.
    //TODO: validate that the Definition Feature Model Diagram property of a feature points to a diagram containing the reference feature.

    /// <summary>
    /// Implements the Feature Model domain root.
    /// </summary>
    [ValidationState(ValidationState.Enabled)]
    public partial class FeatureModel {

        /// <summary>
        /// Validates that this feature mode contains a root feature.
        /// </summary>
        /// <param name="context">The validation context object.</param>
        [ValidationMethod()]
        public void ValidateRootFeature(ValidationContext context) {
            if (RootFeature == null) {
                context.LogError("This feature model contains no root feature", "", this);
            }
        }

        /// <summary>
        /// Validates that all feature models element can be reached from the root feature.
        /// </summary>
        /// <param name="context"></param>
        [ValidationMethod()]
        public void ValidateAllElementsAreReachable(ValidationContext context) {
            foreach (FeatureModelElement fmElement in this.FeatureModelElements) {
                fmElement.Visited = false;
                Feature feature = fmElement as Feature;
                if (feature != null) {
                    if (feature.ConstrainedFeatures.Count > 0) {
                        // elements that constrain others are considered visited
                        fmElement.Visited = true;
                    }
                    if (feature.IsReference) {
                        //elements defined elsewhere are considered visited
                        fmElement.Visited = true;
                    }
                }
            }
            
            Feature rootFeature = RootFeature;
            if (rootFeature != null) {
                Visit(rootFeature);
            }
            
            List<ModelElement> unreachableFeatures = new List<ModelElement>();

            foreach (FeatureModelElement fmElement in this.FeatureModelElements) {
                if (fmElement.Visited == false) {
                    unreachableFeatures.Add(fmElement);
                }
            }

            if (unreachableFeatures.Count > 0) {
                context.LogError("Unreachable feature model elements found", "", unreachableFeatures.ToArray());
            }
        }
    }
}
